/*
 * Copyright 2021-2022 the original author and authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package cn.edu.tjnu.tutor.system.service;

import cn.edu.tjnu.tutor.system.domain.entity.Group;
import cn.edu.tjnu.tutor.system.domain.extra.UserGroup;
import cn.edu.tjnu.tutor.system.domain.view.GroupApplyVO;
import cn.edu.tjnu.tutor.system.domain.view.GroupReplyVO;
import cn.edu.tjnu.tutor.system.domain.view.GroupVO;
import cn.edu.tjnu.tutor.system.domain.view.UserVO;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.IService;

import java.util.Objects;

/**
 * 导师小组信息服务层。
 *
 * @author 王帅
 * @since 2.0
 */
public interface GroupService extends IService<Group> {

    /**
     * 普通小组类型。
     */
    String DEFAULT = "D";

    /**
     * 实习小组类型。
     */
    String PRACTICAL = "P";

    /**
     * 分页查询导师小组信息。
     *
     * @param userId 用户主键
     * @param page   分页对象
     * @param <E>    分页对象类型
     * @return 分页数据
     */
    <E extends IPage<GroupVO>> E pageVO(Integer userId, E page);

    /**
     * 分页查询导师小组内的成员信息。
     *
     * @param groupId 小组主键
     * @param page    分页对象
     * @return 分页数据
     */
    <E extends IPage<UserVO>> E pageUserVO(Integer groupId, E page);

    /**
     * 分页查询导师小组申请信息。
     *
     * @param userId 用户主键
     * @param page   分页对象
     * @param <E>    分页对象类型
     * @return 分页数据
     */
    <E extends IPage<GroupApplyVO>> E pageApplyVO(Integer userId, E page);

    /**
     * 分页查询已加入导师小组信息。
     *
     * @param userId 用户主键
     * @param page   分页对象
     * @param <E>    分页对象类型
     * @return 分页数据
     */
    <E extends IPage<GroupReplyVO>> E pageReplyVO(Integer userId, E page);

    /**
     * 判断学生是否不在导师的小组内。
     *
     * @param teacherId 导师用户主键
     * @param studentId 学生用户主键
     * @return {@code true} 学生不在导师小组，{@code false} 学生在导师小组
     */
    boolean notIn(Integer teacherId, Integer studentId);

    /**
     * 判断用户是否不拥有指定的小组。
     *
     * @param userId  用户主键
     * @param groupId 小组主键
     * @return {@code true} 用户不拥有小组，{@code false} 用户拥有小组
     * @implSpec 对于导师小组信息服务，该默认实现为：
     * <pre>{@code
     * return !lambdaQuery()
     *         .eq(Group::getUserId, userId)
     *         .eq(Group::getGroupId, groupId)
     *         .exists();
     * }</pre>
     */
    default boolean notOwn(Integer userId, Integer groupId) {
        return !lambdaQuery()
                .eq(Group::getUserId, userId)
                .eq(Group::getGroupId, groupId)
                .exists();
    }

    /**
     * 判断是否包含给定的导师小组名称。
     *
     * @param group 导师小组信息
     * @return {@code true} 包含给定的导师小组名称，{@code false} 不包含给定的导师小组名称
     * @implSpec 对于导师小组信息服务，该默认实现为：
     * <pre>{@code
     * return lambdaQuery()
     *         .eq(Group::getType, group.getType())
     *         .eq(Group::getUserId, group.getUserId())
     *         .eq(Group::getGroupName, group.getGroupName())
     *         .ne(Objects.nonNull(group.getGroupId()), Group::getGroupId, group.getUserId())
     *         .exists();
     * }</pre>
     */
    default boolean containsName(Group group) {
        return lambdaQuery()
                .eq(Group::getType, group.getType())
                .eq(Group::getUserId, group.getUserId())
                .eq(Group::getGroupName, group.getGroupName())
                .ne(Objects.nonNull(group.getGroupId()), Group::getGroupId, group.getUserId())
                .exists();
    }

    /**
     * 判断学生是否可以申请导师小组。
     *
     * @param userId  用户主键
     * @param groupId 小组主键
     * @return {@code true} 可以申请小组，{@code false} 不可以申请小组
     */
    boolean canApply(Integer userId, Integer groupId);

    /**
     * 判断学生是否没有申请过导师小组。
     *
     * @param userId  用户主键
     * @param groupId 小组主键
     * @return {@code true} 没有申请过小组，{@code false} 申请过小组
     */
    boolean isNotApplied(Integer userId, Integer groupId);

    /**
     * 学生申请导师小组。
     *
     * @param entity 实体类
     * @return {@code true} 申请小组成功，{@code false} 申请小组失败
     */
    boolean apply(UserGroup entity);

    /**
     * 学生更新小组申请信息。
     *
     * @param entity 实体类
     * @return {@code true} 更新申请信息成功，{@code false} 更新申请信息失败
     */
    boolean updateApply(UserGroup entity);

    /**
     * 导师同意学生进入导师小组。
     *
     * @param userId  用户主键
     * @param groupId 小组主键
     * @return {@code true} 同意申请成功，{@code false} 同意申请失败
     */
    boolean agree(Integer userId, Integer groupId);

    /**
     * 导师拒绝学生进入导师小组。
     *
     * @param userId  用户主键
     * @param groupId 小组主键
     * @return {@code true} 拒绝申请成功，{@code false} 拒绝申请失败
     */
    boolean reject(Integer userId, Integer groupId);

    /**
     * 为小组绑定小组组长。
     *
     * @param userId  用户主键
     * @param groupId 小组主键
     * @return {@code true} 绑定成功，{@code false} 绑定失败
     */
    boolean bindCaptain(Integer userId, Integer groupId);

    /**
     * 为小组解除小组组长。
     *
     * @param userId  用户主键
     * @param groupId 小组主键
     * @return {@code true} 解除成功，{@code false} 解除失败
     */
    boolean dumpCaptain(Integer userId, Integer groupId);

}